﻿#pragma once

#include <iostream>
#include <string>
#include <limits>
#include <memory.h>
#include "lix/character.h"


namespace lix{

	namespace detail{
		template<class InputIterator, class Predicate>
		InputIterator find_if_not(InputIterator first, InputIterator last, Predicate pred) {
			for ( ; first != last; ++first){
				if (!pred(*first)){
					return first;
				}
			}
			return last;
		}
	}

	//! 固定された文字列上の部分文字列
	//! 
	//! このクラス自身は文字列の寿命を管理しない。
	//! 別途管理された文字列があり、その一部分だけを文字列として情報伝達したい場合に使用する。
	//! 
	//! @tmaram CH char, wchar_t
	template<typename CH>
	class BasicCharSequence{
	public:
		typedef std::basic_string<CH, std::char_traits<CH>, std::allocator<CH> > string_type;
		typedef BasicCharSequence<CH> this_type;
		typedef CH char_type;
		typedef CH value_type;


		//! ポインタ範囲からの生成
		//! 
		//! コンストラクタは先頭ポインタと長さを受ける、ポインタ範囲から生成する場合はこのメソッドを。
		static BasicCharSequence create( const CH* begin, const CH* end ){
			if( ! begin ){
				return BasicCharSequence<CH>();
			}
			size_t lenght = static_cast<size_t>(end - begin);
			return BasicCharSequence<CH>( begin, lenght );
		}

		//! cスタイル文字列からの生成、全体を指す CharSequence を返す。
		//! 
		//! コンストラクタは先頭ポインタと長さを受ける。
		//! これは特殊な例なため、コンストラクタではなく、明示的にこのメソッドを使用するように。
		static BasicCharSequence create( const CH* begin ){
			if( ! begin ){
				return BasicCharSequence<CH>();
			}
			size_t lenght = static_cast<size_t>(std::char_traits<CH>::length( begin ));
			return BasicCharSequence<CH>( begin, lenght );
		}	

		//! std::string からの生成
		static BasicCharSequence create( const string_type& str ){
			return BasicCharSequence<CH>(str.c_str(), str.size());
		}

		//! デフォルトコンストラクタ、NULLを指す。
		BasicCharSequence() 
			: m_pBegin(NULL), m_Length(0)
		{}

		//! 開始位置と文字列長を受けるコンストラクタ。
		BasicCharSequence(const CH* ch, size_t length)
			: m_pBegin(ch), m_Length(length)
		{}

		//! 0 終端文字列の最初から最後までをさすコンストラクタ。
		//! 
		//! 受け取った文字列の寿命に関しては一切考慮しない。
		//! このオブジェクトより長い寿命を持つ文字列であること。
		explicit BasicCharSequence(const CH* ch)
		{
			m_pBegin = ch;
			m_Length = static_cast<size_t>(std::char_traits<CH>::length( ch ));	
		}

		//! std::string の最初から最後までをさすコンストラクタ。
		//! 
		//! 受け取った文字列の寿命に関しては一切考慮しない。
		//! このオブジェクトより長い寿命を持つ文字列であること。
		explicit BasicCharSequence(const string_type& str)
		{
			m_pBegin = str.c_str();
			m_Length = static_cast<size_t>(str.size());	
		}

		//! コピーコンストラクタ
		//! そのまま内容をコピーする。
		BasicCharSequence( const BasicCharSequence& other )
			: m_pBegin( other.m_pBegin ), m_Length( other.m_Length )
		{}

		//! 代入
		//! 
		//! 文字列の寿命はソースとなる文字列の寿命に依存するため、
		//! ソース文字列違う BasicCharSequence を代入するとわけがわからないことになるので注意
		BasicCharSequence& operator=( const BasicCharSequence& other ){
			this->m_pBegin = other.m_pBegin;
			this->m_Length = other.m_Length;
			return *this;
		}

		//! インデクサ
		CH operator[]( size_t index ) const {
			if( isNull()){
				return 0;
			}
			if( index >= m_Length ){
				return 0;
			}
			return this->m_pBegin[index];
		}

		//! 部分文字列をさす BasicCharSequence を返す
		//! 
		//! @param begin  開始文字位置
		//! @param length 長さ、省略時は「最後まで」
		BasicCharSequence subSequence( size_t begin, size_t length = std::numeric_limits<size_t>::max()) const {
			if( begin >= m_Length ){
				return BasicCharSequence<CH>();
			}
			if( isEmpty()){
				return BasicCharSequence<CH>();
			}

			size_t l = m_Length - begin;
			if( l > length ){
				l = length;
			}
			const CH* b = m_pBegin + begin;
			return BasicCharSequence(b, l);
		}

		//! 先頭のみ比較
		bool startsWith( const BasicCharSequence& other )const{
			if( isEmpty()){
				return false;
			}
			if( getLength() < other.getLength()){
				return false;
			}
			return memcmp( m_pBegin, other.m_pBegin, other.getLength() * sizeof( CH )) == 0;
		}
		bool startsWith( const CH* other ) const{
			return startsWith( create( other ));
		}
		bool startsWith( const string_type& other ) const{
			return startsWith( create( other ));
		}



		//! 長さを返す。
		size_t getLength() const {
			if( isNull()){
				return 0;
			}
			return m_Length;
		}
		//! 何も指していないとき true.
		//! 
		//! 空文字列を指している状態では false を返すので注意。
		//! 一般的な用途では isEmpty を使用するべき。
		bool isNull() const {
			return m_pBegin == NULL;
		}

		//! 何も指していないか空文字列の時 true.
		bool isEmpty() const {
			return (( m_pBegin == NULL) || (m_Length == 0 ));
		}







		//! NULL を指すように変更
		void clear(){
			m_pBegin = NULL;
			m_Length = 0;
		}

		//! 入れ替え
		void swap( BasicCharSequence& other ){
			std::swap( this->m_pBegin, other->m_pBegin);
			std::swap( this->m_Length, other->m_Length);
		}

		const CH* begin() const {
			return m_pBegin;
		}

		const CH* end() const {
			if( ! m_pBegin ){
				return NULL;
			}
			return m_pBegin + m_Length;
		}

		//! 文字列化。
		std::basic_string<CH> str() const {
			if( isEmpty()){
				return BasicCharSequence::EmptyString();
			}
			return std::basic_string<CH>( m_pBegin, m_pBegin + m_Length );
		}

		//! trim
		BasicCharSequence trim(){
			if( isEmpty()){
				return BasicCharSequence<CH>();
			}

			const CH* be = begin();
			const CH* en = end();

			while( true ){
				if( en == be ){
					break;
				}
				if( Character::isWhiteSpace( *(en-1) ) ){
					--en;
					continue;
				}
				break;
			}

			be = lix::detail::find_if_not( be, en, Character::isWhiteSpace<CH> );
			return BasicCharSequence::create( be, en );
		}



		//! 同値比較
		//! 
		//! 指している先が文字列として値が等しければ true を返す。
		inline bool operator==( const BasicCharSequence& a ) const{
			if( a.isEmpty() ){
				return this->isEmpty();
			}
			if( a.getLength() != this->getLength()){
				return false;
			}
			if( this->m_pBegin == a.m_pBegin ){
				return true;
			}
			return 0 == std::char_traits<CH>::compare( a.begin(), this->begin(), this->getLength() );
		}

		// 文字列との比較
		inline bool operator==(const string_type& a ) const{
			return this->operator==(  BasicCharSequence::create(a.c_str()));
		}

		inline bool operator==(const CH* a ) const{
			if( a == NULL ){
				return isNull();
			}
			if( std::char_traits<CH>::length( a ) != m_Length ){
				return false;
			}
			return std::char_traits<CH>::compare( a, m_pBegin, m_Length ) == 0;
		}

		//! 大小比較(これは BasicCharSequence 同士以外許さないので全てメンバで)
		bool operator<( const BasicCharSequence& a ) const {
			if( this->isEmpty() ){
				return ! a.isEmpty();
			} 
			size_t length = std::max( this->getLength(), a.getLength());
			return std::char_traits<CH>::compare( a.begin(), this->begin(), length ) < 0;
		}

		bool operator>( const BasicCharSequence& a ) const {
			return ( a < *this );
		}
		bool operator<=( const BasicCharSequence& a ) const {
			return ! ( *this > a);
		}
		bool operator>=( const BasicCharSequence& a ) const {
			return ! ( *this < a);
		}

	private:

		//! 空の文字列を返す
		static const CH* EmptyString(){
			static CH c = 0;
			return &c;
		}

		const CH* m_pBegin;
		size_t  m_Length;
	};





	template<typename CH>
	inline bool operator==( const typename BasicCharSequence<CH>::string_type& a, const BasicCharSequence<CH>& b ){
		return ( BasicCharSequence<CH>::create( a.c_str()) == b );
	}
	template<typename CH>
	inline bool operator==( const CH* p, const BasicCharSequence<CH>& b ){
		return ( b == p );
	}

	template<typename CH>
	inline bool operator!=( const BasicCharSequence<CH>& a, const BasicCharSequence<CH>& b ){
		return ! ( a == b );
	}
	template<typename CH>
	inline bool operator!=( const typename BasicCharSequence<CH>::string_type& a, const BasicCharSequence<CH>& b ){
		return ! ( a == b );
	}
	template<typename CH>
	inline bool operator!=( const BasicCharSequence<CH>& a, const typename BasicCharSequence<CH>::string_type& b ){
		return ! ( a == b );
	}

	template<typename CH>
	inline bool operator!=( const CH* p, const BasicCharSequence<CH>& b ){
		return ! ( b == p );
	}

	template<typename CH>
	inline bool operator!=( const BasicCharSequence<CH>& a, const CH* p  ){
		return ! ( a == p );
	}
	
	//! swap
	template<typename CH>
	inline void swap( BasicCharSequence<CH>& a, BasicCharSequence<CH>& b){
		a.swap(b);
	}
	
	// 出力
	inline std::ostream& operator<<( std::ostream&os, BasicCharSequence<char>& seq ){
		os << seq.str();
		return os;
	}

	// 出力(wchar_t版)
	inline std::wostream& operator<<( std::wostream&os, BasicCharSequence<wchar_t>& seq ){
		os << seq.str();
		return os;
	}

	typedef BasicCharSequence<char> CharSequence;
	typedef BasicCharSequence<wchar_t> WCharSequence;

} // namesapce lix;